package com.koushikdutta.ion;

import com.example.ohosasynclibrary.async.future.Future;
import com.koushikdutta.ion.bitmap.BitmapInfo;
import com.koushikdutta.ion.builder.AnimateGifMode;
import com.koushikdutta.ion.builder.Builders;
import com.koushikdutta.ion.builder.ImageViewFutureBuilder;
import com.koushikdutta.ion.future.ImageViewFuture;
import ohos.agp.animation.Animator;
import ohos.agp.components.Image;
import ohos.agp.components.element.Element;
import ohos.agp.components.element.PixelMapElement;
import ohos.media.image.PixelMap;

/**
 * Created by koush on 7/4/14.
 */
public class IonImageViewRequestBuilder extends IonBitmapRequestBuilder implements Builders.IV.F, ImageViewFutureBuilder {
    Element placeholderDrawable;
    int placeholderResource;
    Element errorDrawable;
    int errorResource;
    Animator inAnimation;
    Animator loadAnimation;
    int loadAnimationResource;
    int inAnimationResource;
    ContextReference.ImageViewContextReference imageViewPostRef;
    boolean fadeIn = true;
    boolean crossfade;
    BitmapDrawableFactory bitmapDrawableFactory = BitmapDrawableFactory.DEFAULT;

    public IonImageViewRequestBuilder(IonRequestBuilder builder) {
        super(builder);
    }

    public IonImageViewRequestBuilder(Ion ion) {
        super(ion);
    }

    @Override
    void reset() {
        super.reset();
        fadeIn = true;
        crossfade = false;
        imageViewPostRef = null;
        placeholderDrawable = null;
        bitmapDrawableFactory = BitmapDrawableFactory.DEFAULT;
        placeholderResource = 0;
        errorDrawable = null;
        errorResource = 0;
        inAnimation = null;
        inAnimationResource = 0;
        loadAnimation = null;
        loadAnimationResource = 0;
    }

    @Override
    protected IonRequestBuilder ensureBuilder() {
        if (builder == null)
            builder = new IonRequestBuilder(ContextReference.fromContext(imageViewPostRef.getContext().getApplicationContext()), ion);
        return builder;
    }

    @Override
    public ImageViewFuture load(String uri) {
        ensureBuilder();
        builder.load(uri);
        return intoImageView(imageViewPostRef.get());
    }

    @Override
    public Future<Image> load(String method, String url) {
        ensureBuilder();
        builder.load(method, url);
        return intoImageView(imageViewPostRef.get());
    }

    IonImageViewRequestBuilder withImageView(Image imageView) {
        if (imageViewPostRef == null || imageViewPostRef.get() != imageView)
            imageViewPostRef = new ContextReference.ImageViewContextReference(imageView);
        return this;
    }

    private IonDrawable setIonDrawable(Image imageView, BitmapFetcher bitmapFetcher, ResponseServedFrom servedFrom) {
        BitmapInfo info = null;
        if (bitmapFetcher != null)
            info = bitmapFetcher.info;
        if (info != null)
            bitmapFetcher = null;

        IonDrawable ret = IonDrawable.getOrCreateIonDrawable(imageView, placeholderResource)
                .setBitmap(info, servedFrom)
                .ion(ion)
                .setBitmapFetcher(bitmapFetcher)
                .setRepeatAnimation(animateGifMode == AnimateGifMode.ANIMATE)
                .setSize(resizeWidth, resizeHeight)
                .setError(errorResource, errorDrawable)
                .setPlaceholder(placeholderResource, placeholderDrawable)
                .setFadeIn(fadeIn || crossfade)
                .setBitmapDrawableFactory(bitmapDrawableFactory)
                .updateLayers();
        if (info != null && info.bitmap != null) {
            ret.setBitmap(info);
            imageView.setPixelMap(info.bitmap);
        } else {
            imageView.setImageElement(ret);
        }
        return ret;
    }

    @Override
    public IonBitmapRequestBuilder fadeIn(boolean fadeIn) {
        this.fadeIn = fadeIn;
        return this;
    }

    @Override
    public ImageViewFuture intoImageView(Image imageView) {
        if (imageView == null)
            throw new NullPointerException("imageView");

        // no uri? just set a placeholder and bail
        if (builder.uri == null) {
            setIonDrawable(imageView, null, ResponseServedFrom.LOADED_FROM_NETWORK).cancel();
            IonLog.e("builder.uri == null==8367");
            return ImageViewFutureImpl.FUTURE_IMAGEVIEW_NULL_URI;
        }

        withImageView(imageView);

        if (crossfade) {
            Element drawable = imageView.getImageElement();
            if (drawable instanceof IonDrawable) {
                IonDrawable ionDrawable = (IonDrawable) drawable;
                drawable = ionDrawable.getCurrentDrawable();
            }
            placeholder(drawable);
        }

        int sampleWidth = resizeWidth;
        int sampleHeight = resizeHeight;
        // see if we need default transforms, or this if the imageview
        // will request the actual size on measure
        if (resizeHeight == 0 && resizeWidth == 0) {
            // set the sample size hints from the current dimensions
            // but don't actually apply a transform.
            // this may be zero, in which case IonDrawable
            // will eventually try again with real dimensions
            // during draw.
            sampleWidth = imageView.getWidth();
            sampleHeight = imageView.getHeight();
        } else {
            addDefaultTransform();
        }

        // executeCache the request, see if we get a bitmap from cache.
        BitmapFetcher bitmapFetcher = executeCache(sampleWidth, sampleHeight);
        if (bitmapFetcher.info != null) {
            doAnimation(imageView, null, 0);
            IonDrawable drawable = setIonDrawable(imageView, bitmapFetcher, ResponseServedFrom.LOADED_FROM_NETWORK);
            drawable.cancel();
            ImageViewFutureImpl imageViewFuture = ImageViewFutureImpl.getOrCreateImageViewFuture(imageViewPostRef, drawable)
                    .setInAnimation(inAnimation, inAnimationResource)
                    .setScaleMode(scaleMode);
            ImageViewFutureImpl.applyScaleMode(imageView, scaleMode);
            imageViewFuture.reset();
            imageViewFuture.setComplete(bitmapFetcher.info.exception, imageView);
            return imageViewFuture;
        }

        IonDrawable drawable = setIonDrawable(imageView, bitmapFetcher, ResponseServedFrom.LOADED_FROM_NETWORK);
        doAnimation(imageView, loadAnimation, loadAnimationResource);
        ImageViewFutureImpl imageViewFuture = ImageViewFutureImpl.getOrCreateImageViewFuture(imageViewPostRef, drawable)
                .setInAnimation(inAnimation, inAnimationResource)
                .setScaleMode(scaleMode);
        imageViewFuture.reset();
        return imageViewFuture;
    }

    private Element getImageViewDrawable() {
        Image iv = imageViewPostRef.get();
        if (iv == null)
            return null;
        return iv.getImageElement();
    }

    @Override
    public PixelMap getBitmap() {
        Element d = getImageViewDrawable();
        if (d == null)
            return null;
        if (d instanceof PixelMapElement)
            return ((PixelMapElement) d).getPixelMap();
        if (!(d instanceof IonDrawable))
            return null;
        IonDrawable id = (IonDrawable) d;
        d = id.getCurrentDrawable();
        if (d instanceof PixelMapElement)
            return ((PixelMapElement) d).getPixelMap();
        return null;
    }

    @Override
    public BitmapInfo getBitmapInfo() {
        Element d = getImageViewDrawable();
        if (d == null)
            return null;
        if (!(d instanceof IonDrawable))
            return null;
        IonDrawable id = (IonDrawable) d;
        return id.getBitmapInfo();
    }


    @Override
    public IonImageViewRequestBuilder crossfade(boolean crossfade) {
        this.crossfade = crossfade;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder placeholder(Element drawable) {
        placeholderDrawable = drawable;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder placeholder(int resourceId) {
        placeholderResource = resourceId;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder error(Element drawable) {
        errorDrawable = drawable;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder error(int resourceId) {
        errorResource = resourceId;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder animateIn(Animator in) {
        inAnimation = in;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder animateLoad(Animator load) {
        loadAnimation = load;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder animateLoad(int animationResource) {
        loadAnimationResource = animationResource;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder animateIn(int animationResource) {
        inAnimationResource = animationResource;
        return this;
    }

    @Override
    public IonImageViewRequestBuilder bitmapDrawableFactory(BitmapDrawableFactory bitmapDrawableFactory) {
        this.bitmapDrawableFactory = bitmapDrawableFactory;
        return this;
    }
}
